﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using System.Xml.Linq;
using Mindfor.Web.Data;
using Mindfor.Web.Models;
using Mindfor.Web.Routing;
using NHibernate.Linq;
using NHibernate;

namespace Mindfor.Web.Modules.System.Controllers
{
	/// <summary>
	/// Represents controller for displaying standart text pages from database.
	/// </summary>
	public class SystemController : CmsController
	{
		static Dictionary<string, XDocument> s_siteMaps = new Dictionary<string, XDocument>();

		/// <summary>
		/// Shows standart text page view.
		/// Model is PageText.
		/// </summary>
		/// <returns>ViewResult.</returns>
		[UrlRouteSkip]
		public ActionResult TextPage(int pageId)
		{
			// find page text
			if (CurrentPageText == null)
				return HttpNotFound();

			// if url set => redirect
			if (!String.IsNullOrEmpty(CurrentPageText.Url))
				return Redirect(CurrentPageText.Url);
			
			// show page
			ViewData.Model = CurrentPageText;
			return View();
		}

		/// <summary>
		/// Returns NotFound action result which renders "NotFound" view.
		/// </summary>
		[UrlRouteSkip]
		public ActionResult NotFound()
		{
			return HttpNotFound();
		}

		/// <summary>
		/// Restarts application and redirects user to returnUrl.
		/// </summary>
		/// <param name="returnUrl">Url to redirect user to. If null then user is redirected to main page.</param>
		[UrlRoute(Path="Admin")]
		[CmsAuthorize(CmsRoles.Administrator)]
		[AdminLink("Перезагрузить сайт", "Системные")]
		public ActionResult Restart(string returnUrl)
		{
			if (String.IsNullOrEmpty(returnUrl))
			{
				if (Request.UrlReferrer != null)
					returnUrl = Request.UrlReferrer.ToString();
				else
					returnUrl = "/";
			}
			CmsApplication.Restart();
			return Redirect(returnUrl);
		}

		[AdminLink]
		[CmsAuthorize]
		[UrlRoute("", Path="Admin")]
		public ActionResult Dashboard()
		{
			return View();
		}

		/// <summary>
		/// Returns result which renders Routes view.
		/// Model is RouteCollection.
		/// </summary>
		[UrlRoute(Path="Admin")]
		[CmsAuthorize(CmsRoles.Administrator)]
		[AdminLink("Системные маршруты", "Системные")]
		public ActionResult Routes(string route)
		{
			RoutesModel model = new RoutesModel(RouteTable.Routes);
			ViewData.Model = model;

			if (!String.IsNullOrEmpty(route))
			{
				// rewrite path to find match routes
				if (route[0] != '/')
					route = "/" + route;
				this.HttpContext.RewritePath(route);

				// find match routes
				List<RouteData> matches = new List<RouteData>();
				foreach (RouteBase r in model.Routes)
				{
					RouteData rd = r.GetRouteData(this.HttpContext);
					if (rd != null)
						matches.Add(rd);
				}
				model.MatchRoutes = matches;
			}

			return View();
		}

		/// <summary>
		/// Returns xml file that contains site map for request domain.
		/// </summary>
		[UrlRoute("", Name="SiteMap", Path="sitemap.xml")]
		public ActionResult SiteMap()
		{
			XDocument map;
			string siteUrl = SiteUrl.ToString().ToLower();
			
			// load map from memory
			if (s_siteMaps.ContainsKey(siteUrl))
				map = s_siteMaps[siteUrl];
			// generate map
			else
			{
				map = new XDocument();
				s_siteMaps[siteUrl] = map;

				XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
				XNamespace nsXsi = "http://www.w3.org/2001/XMLSchema-instance";
				XElement root = new XElement(ns + "urlset",
					new XAttribute("xmlns", ns.NamespaceName),
					new XAttribute(XNamespace.Xmlns + "xsi", nsXsi.NamespaceName),
					new XAttribute(nsXsi + "schemaLocation", "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd")
				);
				map.Add(root);
				root.Add(SiteMapLocationsForPages(ns));
			}

			// return xml
			return Xml(map);
		}

		/// <summary>
		/// Generates site map locations for required pages. If pages null then generates for root pages.
		/// </summary>
		/// <param name="pages">Pages to generate locations for.</param>
		private IEnumerable<XElement> SiteMapLocationsForPages(XNamespace ns, IEnumerable<Page> pages = null)
		{
			// load root pages
			if (pages == null)
			{
				pages = Data.Query<Page>().GetRootPages()
					.OrderBy(r => r.Sort)
					.ToList()
					.Where(r => r.HasAccess(null))
					.ToList();
			}

			// add each page
			List<XElement> list = new List<XElement>();
			foreach (Page page in pages)
			{
				// add page
				Uri url = new Uri(SiteUrl, Url.Page(page.Id));
				list.Add(
					new XElement(ns + "url",
						new XElement(ns + "loc", url))
				);

				// add children
				List<Page> childPages = page.ChildPages
					.OrderBy(r => r.Sort)
					.ToList()
					.Where(r => r.HasAccess(null))
					.ToList();
				if (childPages.Count > 0)
					list.AddRange(SiteMapLocationsForPages(ns, childPages));
			}

			// return
			return list;
		}

		/// <summary>
		/// Returns captcha image by captcha key.
		/// </summary>
		/// <param name="key">Captcha key.</param>
		[UrlRoute("Captcha/{key}", Name="Captcha")]
		public FileResult Captcha(string key)
		{
			// get text
			string text = null;
			try
			{
				text = CaptchaManager.DecryptTextFromKey(key);
			}
			catch { }

			if (text == null)
				return null;

			// generate captcha image
			Bitmap img = CaptchaManager.GenerateImage(150, 30, 12, text);
			byte[] bytes = img.SaveImage(ImageFormat.Jpeg, 50);
			return new FileContentResult(bytes, "image/jpeg");
		}
	}
}
